package com.mchat.wsserver.handler;

import com.mchat.user.service.IUserService;
import com.mchat.wsserver.OnlineUserMap;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtParser;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketCloseStatus;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.util.AttributeKey;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;

@ChannelHandler.Sharable
@Slf4j
public class AuthHandler extends ChannelInboundHandlerAdapter {

    private final JwtParser parser;
    private final IUserService userService;
    public static final AttributeKey<Long> TOKEN_ID = AttributeKey.valueOf("tokenId");
    public AuthHandler(JwtParser parser, IUserService userService) {
        this.parser = parser;
        this.userService = userService;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if(msg instanceof TextWebSocketFrame){
            try{
                Claims claims = parser.parseClaimsJws(((TextWebSocketFrame) msg).text()).getBody();
                long id = Long.parseLong(claims.getSubject());
                long tokenId = Long.parseLong(claims.getId());
                userService.validUser(id,claims).subscribe(valid->{
                    if(valid){
                        OnlineUserMap.add(id,ctx.channel());
                        ctx.channel().attr(TOKEN_ID).set(tokenId);
                        ctx.channel().pipeline().remove(this);
                        ctx.channel().pipeline().addLast(new WebSocketFrameHandler(id));
                        ctx.writeAndFlush(new TextWebSocketFrame("success"));
                    }
                    else {
                        reject(ctx.channel());
                    }
                },err->{
                    reject(ctx.channel());
                });

            }
            catch (Exception e) {
                log.warn("JWT parse error: {}", e.getMessage());
                reject(ctx.channel());
            }finally{
                ReferenceCountUtil.release(msg);
            }
        }else{
            ctx.fireChannelRead(msg);
        }

    }
    private void reject (Channel channel){
        channel.writeAndFlush(new CloseWebSocketFrame(new WebSocketCloseStatus(4000,""))).addListener(ChannelFutureListener.CLOSE);
    }
}
